package tools

import (
	"encoding/json"
	"golang-websocket-service/handler"
	"log"
	"time"

	"github.com/olahol/melody"
)

/*
 +----------------------------------------------------------------------
 + Title        : websocketServer
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2024-09-22
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : websocket 服务
 +----------------------------------------------------------------------
*/
type WebsocketServer struct {
	WebsocketSrv *melody.Melody
}

/**
 * 创建 WEBSOCKET SERVER
 *
 * @return *WebsocketServer
 * @author huwl
 */
func NewWebsocketServer() *WebsocketServer {
	websocketServer := &WebsocketServer{WebsocketSrv: melody.New()}

	// 监听连接
	websocketServer.OnConnect()

	// 监听消息
	websocketServer.OnMessage()

	// 监听关闭
	websocketServer.OnClose()

	// 监听断开
	websocketServer.OnDisconnect()
	return websocketServer
}

/**
 * 监听连接
 *
 * @author huwl
 */
func (ws *WebsocketServer) OnConnect() {
	// melody.Session 是客户端对象的会话，保存了特定客户端相关的内容
	ws.WebsocketSrv.HandleConnect(func(s *melody.Session) {
		log.Println(" -------------- 开始处理连接 -------------- ")

		// 获取请求参数
		// log.Println("Session.Request: ", s.Request)
		uid := s.Request.URL.Query().Get("uid")
		group := s.Request.URL.Query().Get("group")
		username := s.Request.URL.Query().Get("username")
		token := s.Request.URL.Query().Get("token")

		// 中可以用来临时记录一些客户信息
		// melody.Session.Keys
		s.Set("uid", uid)
		s.Set("group", group)
		s.Set("username", username)
		s.Set("token", token)

		// 获取连接会话存储的临时信息
		log.Println("Session.Keys: ", s.Keys)

		// 获取本地服务地址 + 客户端地址
		log.Println("LocalAddr: ", s.LocalAddr(), "RemoteAddr: ", s.RemoteAddr())
	})
}

/**
 * 监听消息
 *
 * @author huwl
 */
func (ws *WebsocketServer) OnMessage() {
	ws.WebsocketSrv.HandleMessage(func(s *melody.Session, msg []byte) {
		log.Println(" -------------- 开始处理处理消息 -------------- ")
		log.Println("消息数据：", string(msg))
		log.Println("Keys = ", s.Keys)
		log.Println("Header = ", s.Request.Header)
		// log.Println("Request = ", s.Request)
		// log.Println("IsClosed = ", s.IsClosed())
		// log.Println("Method = ", s.Request.Method)
		// log.Println("RemoteAddr = ", s.RemoteAddr())
		// log.Println("URL = ", s.Request.URL)
		// log.Println("from_uid = ", s.Request.URL.Query().Get("from_uid"))

		// 将消息写入会话
		// s.Write(msg)

		// 将二进制消息写入会话
		// s.WriteBinary(msg)

		// // 向所有会话广播文本消息
		// ws.Broadcast(msg)

		// // 向所有会话广播二进制消息
		// ws.BroadcastBinary(msg)

		// // 向fn返回true的所有会话广播一个二进制消息
		// ws.BroadcastBinaryFilter(msg, func(s *melody.Session) bool {
		// 	return true
		// })

		// // 向会话s以外的所有会话广播二进制消息
		// ws.BroadcastBinaryOthers(msg, s)

		// // 向除会话s之外的所有会话广播文本消息
		// ws.BroadcastOthers(msg, s)

		// 解析消息
		message := map[string]interface{}{}
		json.Unmarshal(msg, &message)

		// 获取事件
		eventType := message["event_type"]
		log.Println("eventType =", eventType)

		// 判断消息事件类型
		switch eventType {
		case "chat": // 一对一聊天事件
			// 向fn返回true的所有会话广播文本消息
			ws.WebsocketSrv.BroadcastFilter(msg, func(q *melody.Session) bool {
				log.Println("s =", s)
				log.Println("q =", q)
				message := map[string]interface{}{}
				json.Unmarshal(msg, &message)
				log.Println("to_uid =", message["to_uid"])
				// 获取当前用户方式一
				log.Println("uid =", q.Request.URL.Query().Get("uid"))

				// 获取当前用户方式二
				uid, ok := q.Get("uid")
				if ok {
					log.Println("uid =", uid)
				}
				// 发送给指定客户端,获取消息中的目标用户(客户端)与每个用户进行对比
				// 当匹配成功即可发送到目标用户(客户端)
				// 这里一定要注意传输的参数类型一定要一样，否则无法匹配成功
				return message["to_uid"].(string) == q.Request.URL.Query().Get("uid")
			})
		case "orderExpired": // 发送订单过期消息给指定客户端事件
			handler.OrderExpired{}.SendMessage(ws.WebsocketSrv, s, msg)
		case "broadcasting": // 发送广播所有客户端事件
			ws.WebsocketSrv.Broadcast(msg)
		case "ping": // 处理客户端心跳事件
			data, _ := json.Marshal(map[string]interface{}{
				"event_type":  "pong",
				"create_time": time.Now().Format("2006-01-02 15:04:05"),
			})
			s.Write(data)
		}
	})
}

/**
 * 监听错误
 *
 * @author huwl
 */
func (ws *WebsocketServer) OnError() {
	ws.WebsocketSrv.HandleError(func(s *melody.Session, err error) {
		log.Println(" -------------- 开始处理错误 -------------- ")
		log.Println("错误信息：", err.Error())
	})
}

/**
 * 监听关闭
 *
 * @author huwl
 */
func (ws *WebsocketServer) OnClose() {
	ws.WebsocketSrv.HandleClose(func(s1 *melody.Session, i int, s2 string) error {
		log.Println(" -------------- 开始处理关闭连接 -------------- ")
		log.Println("i =", i)
		log.Println("s =", s2)
		return s1.Close()
	})
}

/**
 * 监听断开
 *
 * @author huwl
 */
func (ws *WebsocketServer) OnDisconnect() {
	ws.WebsocketSrv.HandleDisconnect(func(s *melody.Session) {
		log.Println(" -------------- 开始处理断开连接 -------------- ")
		s.Close()
	})
}
